package com.xtravel.common.widget;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.os.AsyncTask;
import android.os.Environment;
import android.util.AttributeSet;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import com.xtravel.R;
import com.xtravel.common.helper.EncryptHelper;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

public class  AsyncImageView extends ImageView {
    private static final int DANGER_SIZE = 60;

    private static HashMap<String, Bitmap> bitmapMap = new HashMap<String, Bitmap>();
    private static List<BitmapCache> caches = new ArrayList<BitmapCache>();

    public AsyncImageView(Context context) {
        super(context);
    }

    public AsyncImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public AsyncImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public void setImageUrl(String url) {
        setImageUrl(url, null);
    }

    public void setImageUrl(String url, OnImageLoadListener listener) {
        new AsyncLoadImageTask(this, listener).execute(url);
    }

    public void setImageUrl(String url, Integer width, Integer height, OnImageLoadListener listener) {
        width = dip2px(getContext(), width);
        height = dip2px(getContext(), height);
        new AsyncLoadImageTask(this, width, height, listener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url);
    }

    public String getLocalFilePath(String url, Integer width, Integer height) {
        try {
            File dirPath = Environment.getExternalStorageDirectory();
            String dir = dirPath.toString() + "/xtravel/cache/images";
            dirPath = new File(dir);
            if (!dirPath.exists()) {
                dirPath.mkdirs();
            }
            String filePath = dirPath.toString() + "/" + EncryptHelper.getMd5String(url) + "_" + width + "x" + height;
            return filePath;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public void saveBitmap(Bitmap bitmap, String filePath) throws IOException {
        File file = new File(filePath);
        FileOutputStream out;
        try {
            file.createNewFile();
            out = new FileOutputStream(file);
            if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)) {
                out.flush();
                out.close();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private Bitmap getBitmap(String url) {
        if (bitmapMap.containsKey(url)) {
            return bitmapMap.get(url);
        }

        return null;
    }

    private void addBitmapCache(String url, Bitmap bitmap) {
        if (caches.size() >= DANGER_SIZE) {
            int size = caches.size();
            for (int i = size - 1; i >= DANGER_SIZE - 1; i--) {
                BitmapCache cache = caches.get(i);
                bitmapMap.remove(cache.url);
                caches.remove(i);
            }
        }

        BitmapCache cache = new BitmapCache();
        cache.url = url;
        cache.bitmap = bitmap;
        cache.createdTime = new Date().getTime();

        caches.add(0, cache);
        bitmapMap.put(url, bitmap);
    }

    public class BitmapCache {
        public String url;
        public Bitmap bitmap;
        public Long createdTime;
    }

    public class AsyncLoadImageTask extends AsyncTask<String, Integer, Bitmap> {

        private Integer width = 0;
        private Integer height = 0;

        private Boolean hasCache = false;

        private ImageView imgView;
        private OnImageLoadListener listener;

        public AsyncLoadImageTask(ImageView view, OnImageLoadListener listener) {
            this.imgView = view;
            this.listener = listener;
        }

        public AsyncLoadImageTask(ImageView view, Integer width, Integer height, OnImageLoadListener listener) {
            this.imgView = view;
            this.listener = listener;

            this.width = width;
            this.height = height;
        }

        @Override
        protected Bitmap doInBackground(String... args) {
            String url = args[0];
            Bitmap bitmap = getBitmap(url);

            hasCache = bitmap != null;
            if (!hasCache) {
                String localFilePath = getLocalFilePath(url, width, height);

                if (localFilePath != null) {
                    File file = new File(localFilePath);
                    if (file.exists()) {
                        bitmap = BitmapFactory.decodeFile(localFilePath);
                        addBitmapCache(url, bitmap);
                        return bitmap;
                    }
                }

                try {
                    URL myFileUrl = new URL(args[0]);
                    HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection();
                    conn.setConnectTimeout(6000);
                    conn.setDoInput(true);
                    conn.setUseCaches(false);
                    if (conn.getResponseCode() == 200) {
                        InputStream is = conn.getInputStream();
                        if (width > 0 && height > 0) {
                            /*
                            BitmapFactory.Options options = new BitmapFactory.Options();
                            options.inJustDecodeBounds = true;
                            BitmapFactory.decodeStream(is, null, options);

                            if (options.outWidth > width * 2) {
                                options.inSampleSize = options.outWidth * 2 / width;
                            }

                            options.inJustDecodeBounds = false;
                            */
                            bitmap = BitmapFactory.decodeStream(is);
                            bitmap = ImageCrop(bitmap);
                            bitmap = resizeImage(bitmap, width, height);
                        } else {
                            bitmap = BitmapFactory.decodeStream(is);
                        }
                        is.close();

                        saveBitmap(bitmap, localFilePath);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }

                addBitmapCache(url, bitmap);
            }

            return getBitmap(url);
        }

        @Override
        protected void onPostExecute(Bitmap result) {
            if (listener != null) {
                listener.onLoaded(imgView, result);
            }

            if (imgView != null && result != null) {
                imgView.setImageBitmap(result);

                if (!hasCache) {
                    imgView.startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.fade_in));
                }
            }

            //Log.d("??????", caches.size() + ":" + bitmapMap.size());
            super.onPostExecute(result);
        }
    }

    public interface OnImageLoadListener {
        void onLoaded(ImageView view, Bitmap bitmap);
    }

    public Bitmap resizeImage(Bitmap bitmap, int w, int h) {
        Bitmap BitmapOrg = bitmap;
        int width = BitmapOrg.getWidth();
        int height = BitmapOrg.getHeight();

        if (width > height) {
            h = height * h / width;
        } else {
            w = width * w / height;
        }

        int newWidth = w;
        int newHeight = h;

        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;

        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight);
        // if you want to rotate the Bitmap
        // matrix.postRotate(45);
        Bitmap resizedBitmap = Bitmap.createBitmap(BitmapOrg, 0, 0, width,
                height, matrix, true);
        return resizedBitmap;
    }

    public Bitmap ImageCrop(Bitmap bitmap) {
        int w = bitmap.getWidth(); // 得到图片的宽，高
        int h = bitmap.getHeight();

        int rh = h > w ? w : h;

        int retX = 0;
        int retY = 0;

        //下面这句是关键
        return Bitmap.createBitmap(bitmap, retX, retY, w, rh, null, false);
    }

    public int dip2px(Context context, float dpValue) {
        float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

}
